﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive;
using System.Reactive.Linq;

using VSTalk.Engine.ViewModel.ContactList.ClientResources;
using VSTalk.Engine.ViewModel.ContactList.Filter;
using VSTalk.Engine.ViewModel.ContactList.Order;
using VSTalk.Tools;

namespace VSTalk.Engine.ViewModel.ContactList
{
    public class SearchQueryBehavior : IResourceComparator, IResourceFilter, IObservableResource
    {
        private readonly IQuerySource _querySource;
        
        public SearchQueryBehavior(IQuerySource querySource)
        {
            _querySource = querySource;
        }

        public IObservable<Unit> Trigger
        {
            get
            {
                return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
                    h => _querySource.PropertyChanged += h, 
                    h => _querySource.PropertyChanged -= h)
                    .SelectMany(Observable.Return(Unit.Default));
            }
        }

        public IComparer<IClientResource> Comparator
        {
            get { return new DelegateComparer<IClientResource>(Compare); }
        }

        private int Compare(IClientResource x, IClientResource y)
        {
            var xName = GetName(x);
            var yName = GetName(y);
            if (xName == null || yName == null)
            {
                return 0;
            }
            var xMeasure = NameMeasure(xName);
            var yMeasure = NameMeasure(yName);
            if (xMeasure != yMeasure)
            {
                return xMeasure > yMeasure ? 1 : -1;
            }
            return 0;
        }

        public string GetName(IClientResource resource)
        {
            if (resource is RoomResourceViewModel)
            {
                return ((RoomResourceViewModel) resource).Room.Name;
            }
            if (resource is InterlocutorResourceViewModel)
            {
                return ((InterlocutorResourceViewModel) resource).Interlocutor.Name;
            }
            return null;
        }

        public int NameMeasure(string name)
        {
            if (string.IsNullOrEmpty(_querySource.SearchQuery))
            {
                return 0;
            }
            var index = name.IndexOf(_querySource.SearchQuery, StringComparison.OrdinalIgnoreCase);
            return index == -1 ? int.MaxValue : index;
        }

        public FilterResult Apply(IClientResource clientResource)
        {
            var name = GetName(clientResource);
            
            if (name == null)
            {
                return FilterResult.Rejected;
            }

            if (string.IsNullOrEmpty(_querySource.SearchQuery))
            {
                return FilterResult.Rejected;
            }

            var index = name.IndexOf(_querySource.SearchQuery, StringComparison.OrdinalIgnoreCase);
            if (index == -1)
            {
                return FilterResult.Rejected;
            }
            return FilterResult.Accepted;
        }
    }
}